package com.ugood.utils;

import org.apache.commons.lang3.StringUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;


/**
 * 时间工具类
 * Created by lwy on 2017/11/28.
 */
public class DateUtils {


	public static DateTimeFormatter format_ymdhms = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

	private static DateTimeFormatter format_ymdhmssss = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");

	private static DateTimeFormatter format_ymds = DateTimeFormatter.ofPattern("yyyyMMdd");

	private static DateTimeFormatter formatymdhms = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");

	public static DateTimeFormatter format_ymd = DateTimeFormatter.ofPattern("yyyy-MM-dd");

	public static DateTimeFormatter format_ym = DateTimeFormatter.ofPattern("yyyy-MM-dd");
	public static DateTimeFormatter format_md = DateTimeFormatter.ofPattern("MM-dd");
	public static SimpleDateFormat format_m = new SimpleDateFormat("MM-dd");

	public static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
	public static SimpleDateFormat format_yyyyMMddhhmm = new SimpleDateFormat("yyyy-MM-dd hh:mm");
	public static SimpleDateFormat format_yyyyMMddHHmm = new SimpleDateFormat("yyyy-MM-dd HH:mm");
	public static SimpleDateFormat formatymd = new SimpleDateFormat("yyyy-MM-dd");
	public static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-M-d");
	public static SimpleDateFormat yyyy = new SimpleDateFormat("yyyy");
	public static SimpleDateFormat sdf_ymd = new SimpleDateFormat("yyyy年MM月dd日");
	public static SimpleDateFormat sdf_ymds = new SimpleDateFormat("yyyy.MM.dd");


	private static ThreadLocal<SimpleDateFormat> local = new ThreadLocal<SimpleDateFormat>();

	public static Date parse(String str) throws Exception {
		SimpleDateFormat sdf = local.get();
		if (sdf == null) {
			sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
			local.set(sdf);
		}
		return sdf.parse(str);
	}

	public static String format(Date date) {
		SimpleDateFormat sdf = local.get();
		if (sdf == null) {
			sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			local.set(sdf);
		}
		return sdf.format(date);
	}

	/**
	 * 获取当前时间
	 *
	 * @return
	 * @throws Exception
	 */
	public static LocalDateTime getCurrentDate() {
		LocalDateTime now = LocalDateTime.now();
		return now;
	}


	/**
	 * 获取当前时间字符串，格式为yyyy-MM-dd HH:mm:ss
	 *
	 * @return
	 */
	public static String getCurrentDateStr() {
		String nowtime = getCurrentDate().format(format_ymdhms);
		return nowtime;
	}

	/**
	 * 获取前几个小时的时间
	 *
	 * @param hours
	 * @return
	 */
	public static String getLastHourDateStr(long hours) {
		return LocalDateTime.now().minusHours(hours).format(format_ymdhms);
	}

	/**
	 * 获取当前时间字符串，格式为yyyyMMdd
	 *
	 * @return
	 */
	public static String getCurrentDateString() {
		String nowtime = getCurrentDate().format(format_ymds);
		return nowtime;
	}

	/**
	 * @param days
	 * @return
	 */
	public static String getNextDayDateStr(int days) {
		return LocalDateTime.now().plusDays(days).format(format_ymdhms);
	}

	/**
	 * @param days
	 * @return
	 */
	public static String getNextDayDateYMD(int days) {
		return LocalDateTime.now().plusDays(days).format(format_ymds);
	}

	public static Date getNextDayDate(int days) {
		LocalDateTime localDateTime = LocalDateTime.now().plusDays(days);
		ZoneId zone = ZoneId.systemDefault();
		Instant instant = localDateTime.atZone(zone).toInstant();
		Date date = Date.from(instant);
		return date;
	}

	/**
	 * 获取当前时间字符串，格式为yyyy-MM-dd
	 *
	 * @return
	 */
	public static String getCurrentDateStrymd() {
		String nowtime = getCurrentDate().format(format_ymd);
		return nowtime;
	}

	public static String getCurrentDateStr_MS() {
		String nowtime = getCurrentDate().format(format_ymdhmssss);
		return nowtime;
	}

	public static String getCurrentDateStr_HMS() {
		String nowtime = getCurrentDate().format(formatymdhms);
		return nowtime;
	}

	/**
	 * 获取当前时间long值
	 *
	 * @return
	 */
	public static String getDataLong(Long second) {
		String format = format(new Date(second));
		return format;
	}

	/**
	 * 获取当前时间long值
	 *
	 * @return
	 */
	public static long getCurrentDataLong() {
		return new Date().getTime();
	}


	/**
	 * 获取当前时间
	 *
	 * @param format
	 * @return
	 * @throws Exception
	 */
	public static Date getCurrentDate(SimpleDateFormat format) throws Exception {
		String tempDate = format.format(new Date());
		return format.parse(tempDate);
	}

	/**
	 * @param date
	 * @param newFormat
	 * @return
	 * @throws Exception
	 */
	public static Date getDate(Date date, SimpleDateFormat newFormat) throws Exception {
		String tempDate = newFormat.format(date);
		return newFormat.parse(tempDate);
	}

	public static String format(Date date, SimpleDateFormat format) {
		if (null == date) {
			return "";
		}
		return format.format(date);
	}

	/**
	 * 将给定的时间秒转换为中文格式的时分秒
	 *
	 * @param second
	 * @return
	 */
	public static String formatSecond_ZH_HMS(Integer second) {
		String result = "0秒";
		if (null != second) {
			int hours = (int) (second / (60 * 60));
			int minutes = (int) (second / 60 - hours * 60);
			int seconds = (int) (second - minutes * 60 - hours * 60 * 60);

			String format;
			Object[] array;

			if (hours > 0) {
				format = "%1$,d时%2$,d分%3$,d秒";
				array = new Object[]{hours, minutes, seconds};
			} else if (minutes > 0) {
				format = "%1$,d分%2$,d秒";
				array = new Object[]{minutes, seconds};
			} else {
				format = "%1$,d秒";
				array = new Object[]{seconds};
			}
			result = String.format(format, array);
		}
		return result;
	}

	/**
	 * 对日期进行加法操作
	 *
	 * @param date
	 * @param days
	 * @return
	 */
	public static Date addDay(Date date, Integer days) {
		if (null != date) {
			Calendar cal = Calendar.getInstance();
			cal.setTime(date);
			cal.add(Calendar.DATE, days);
			return cal.getTime();
		}
		return null;
	}

	/**
	 * 对月份进行操作（正数为添加，负数为减）
	 *
	 * @param dateLong
	 * @param month
	 * @return
	 */
	public static Long operateDateMonth(Long dateLong, Integer month) {
		if (null != dateLong) {
			Calendar cal = Calendar.getInstance();
			cal.setTime(new Date(dateLong));
			cal.add(Calendar.MONTH, month);
			return cal.getTime().getTime();
		}
		return null;
	}

	/**
	 * 对日期进行加法操作
	 *
	 * @param date
	 * @param hours
	 * @return
	 */
	public static Date addHours(Date date, Integer hours) {
		if (null != date) {
			Calendar cal = Calendar.getInstance();
			cal.setTime(date);
			cal.add(Calendar.HOUR_OF_DAY, hours);
			return cal.getTime();
		}
		return null;
	}

	/**
	 * 比较两个日期的大小
	 *
	 * @param date1
	 * @param date2
	 * @return 日期相等，返回0；前者大，返回1；后者大，返回-1；
	 */
	public static int dateCompare(Date date1, Date date2) {
		Calendar c1 = Calendar.getInstance();
		c1.setTime(date1);

		Calendar c2 = Calendar.getInstance();
		c2.setTime(date2);

		return c1.compareTo(c2);
	}

	/**
	 * 判断当前日期是否在指定日期区域内(包含起止日期) [startDate,endDate]
	 * <p/>
	 * [null,null] --> return 1;
	 *
	 * @param now
	 * @param startDate
	 * @param endDate
	 * @return -1：超出并小于startDate；0:在范围内；1：超出并大于endDate；
	 */
	public static int validateDate(Date now, Date startDate, Date endDate) {
		if (null == startDate && null == endDate) {
			return 0;
		}
		if (null == startDate) {
			//当前时间大于endDate
			if (dateCompare(now, endDate) == 1) {
				return 1;
			} else {
				return 0;
			}
		} else {
			if (null == endDate) {
				//当前时间小于startDate
				if (dateCompare(startDate, now) == 1) {
					return -1;
				} else {
					return 0;
				}
			} else {
				if (dateCompare(startDate, now) == 1) {
					return -1;
				} else if (dateCompare(now, endDate) == 1) {
					return 1;
				} else {
					return 0;
				}
			}
		}
	}

	/**
	 * 计算两个日期先差多少秒
	 *
	 * @param pre   前一个日期
	 * @param after 后一个日期
	 * @return
	 */
	public static long calTimeDifference(Date pre, Date after) {
		return (after.getTime() - pre.getTime()) / 1000;
	}

	/**
	 * （某个时间减去多少天 XXXXX）这个注释错了，应该是某个时间添加几天
	 * <p>
	 * 得到年月日
	 *
	 * @param date
	 * @param days
	 * @return
	 */
	public static String getMinusDate(Date date, int days) {
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.DAY_OF_MONTH, days);
		int year = calendar.get(Calendar.YEAR);
		int month = calendar.get(Calendar.MONTH) + 1;
		int day = calendar.get(Calendar.DATE);

		if (month < 10) {
			if (day < 10) {
				return year + "-0" + (month) + "-0" + day;
			} else {
				return year + "-0" + (month) + "-" + day;
			}

		} else {
			if (day < 10) {
				return year + "-" + (month) + "-0" + day;
			} else {
				return year + "-" + (month) + "-" + day;
			}
		}

	}

	/**
	 * 某个时间减去多少小时
	 * 得到年月日某时
	 *
	 * @param date
	 * @param hour
	 * @return
	 */
	public static String getMinusHour(Date date, int hour) {
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.HOUR_OF_DAY, hour);
		int year = calendar.get(Calendar.YEAR);
		int month = calendar.get(Calendar.MONTH) + 1;
		int day = calendar.get(Calendar.DATE);
		int hours = calendar.get(Calendar.HOUR_OF_DAY);

		if (month < 10) {
			if (day < 10) {
				return year + "-0" + (month) + "-0" + day + " " + hours;
			} else {
				return year + "-0" + (month) + "-" + day + " " + hours;
			}

		} else {
			if (day < 10) {
				return year + "-" + (month) + "-0" + day + " " + hours;
			} else {
				return year + "-" + (month) + "-" + day + " " + hours;
			}
		}

	}

	/**
	 * 计算两个时间相差的小时
	 *
	 * @param stardate
	 * @param enddate
	 * @return DaysSecondsBo
	 */
	public static long getHours(Date stardate, Date enddate) {
		long nh = 1000 * 60 * 60;//一小时的毫秒数
		long diff = enddate.getTime() - stardate.getTime();
		long hour = diff / nh;//计算差多少小时
		return hour;
	}

	/**
	 * 获取日期相差天数
	 *
	 * @param beginDateStr
	 * @param endDateStr
	 * @return
	 */
	public static long getDaySub(String beginDateStr, String endDateStr) throws Exception {
		long day = 0;
		Date beginDate = null;
		Date endDate = null;
		if (beginDateStr.length() > 10) {
			beginDate = getDate(beginDateStr, format_ymdhms);
		} else if (beginDateStr.length() == 10) {
			beginDate = formatymd.parse(beginDateStr);
		}

		if (endDateStr.length() > 10) {
			endDate = getDate(endDateStr, format_ymdhms);
		} else if (endDateStr.length() == 10) {
			endDate = formatymd.parse(endDateStr);
		}
		if (beginDate != null && endDate != null) {
			day = (endDate.getTime() - beginDate.getTime()) / (24 * 60 * 60 * 1000);
		}


		return day;
	}

	public static int getWeek(String dateStr) throws Exception {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
		SimpleDateFormat sdfyms = new SimpleDateFormat("yyyy-MM-dd");
		Integer result = 0;
		boolean dateIsYmshms = convertDate(dateStr);
		Date date = new Date();
		if (dateIsYmshms) {
			date = sdf.parse(dateStr);
		} else {
			date = sdfyms.parse(dateStr);
		}
		Calendar c = Calendar.getInstance();
		c.setTime(date);
		int week = c.get(Calendar.DAY_OF_WEEK);
		if (6 == week || 7 == week) {
			result = 2;
		} else {
			result = 1;
		}
		return result;
	}

	/**
	 * 结束时间与当前时间计算相差的月数
	 *
	 * @param enddate
	 * @return
	 */
	public static int getMonthSpace(String enddate, DateTimeFormatter format) {
		LocalDate formatted = LocalDate.parse(enddate, format);
		LocalDate today = LocalDate.now();
		Period per = Period.between(today, formatted);
		if (per.getYears() == 0) {
			return per.getMonths();
		} else if (per.getYears() > 0) {
			return (per.getYears() * 12) + per.getMonths();
		}

		return (per.getYears() * 12) + per.getMonths();
	}


	/**
	 * 将String 格式的时间转换为Date
	 *
	 * @param createDate
	 * @param format     时间格式
	 * @return
	 */
	public static Date getDate(String createDate, DateTimeFormatter format) {
		LocalDateTime dateTime = LocalDateTime.parse(createDate, format);
		ZoneId zone = ZoneId.systemDefault();
		Instant instant = dateTime.atZone(zone).toInstant();
		return Date.from(instant);
	}

	/**
	 * 获取某个时间段之前的时间点
	 *
	 * @return
	 */
	public static String getSomeTimeStapStr(String sign) {
		LocalDateTime beginDateTime = null;
		if (sign.equals("day")) {//一天前时间
			beginDateTime = LocalDateTime.now().minusDays(1L);
		} else if (sign.equals("week")) {
			beginDateTime = LocalDateTime.now().minusWeeks(1L);
		} else if (sign.equals("month")) {
			beginDateTime = LocalDateTime.now().minusMonths(1L);
		} else if (sign.equals("year")) {
			beginDateTime = LocalDateTime.now().minusYears(1L);
		}
		String beginTime = beginDateTime.format(format_ymdhms);
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		try {
			long timestap = sdf.parse(beginTime).getTime();
			beginTime = timestap + "";
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return beginTime;
	}

	public static String getSomeTimeDateStr(String sign) {
		String beginTime = "";
		LocalDateTime beginDateTime = null;
		if (sign.equals("day")) {//一天前时间
			beginDateTime = LocalDateTime.now().minusDays(1L);
		} else if (sign.equals("week")) {
			beginDateTime = LocalDateTime.now().minusWeeks(1L);
		} else if (sign.equals("month")) {
			beginDateTime = LocalDateTime.now().minusMonths(1L);
		} else if (sign.equals("year")) {
			beginDateTime = LocalDateTime.now().minusYears(1L);
		}
		if (beginDateTime != null) {
			beginTime = beginDateTime.format(format_ymdhms);
		}
		return beginTime;
	}

	public static String getTimeDateStr(String sign) {
		Calendar calendar = Calendar.getInstance();
		if (sign.equals("day")) {//一天前时间
			calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) - 0);
		} else if (sign.equals("week")) {
			calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) - 6);
		} else if (sign.equals("month")) {
			calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) - 29);
		} else if (sign.equals("year")) {
			calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) - 364);
		}
		Date today = calendar.getTime();
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		String result = format.format(today);
		return result;
	}

	public static Date getTimeDate(String sign) {
		Calendar calendar = Calendar.getInstance();
		if (sign.equals("day")) {//一天后时间
			calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) + 0);
		} else if (sign.equals("week")) {
			calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) + 6);
		} else if (sign.equals("month")) {
			calendar.set(Calendar.DATE, calendar.getActualMaximum(Calendar.DATE));
		} else if (sign.equals("year")) {
			calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) + 364);
		}
		return calendar.getTime();
	}


	/**
	 * 获取失效时间点（在什么时间失效）
	 *
	 * @param minutes 有效分钟数
	 * @return
	 */
	public static LocalDateTime getInvalidLocalDateTime(Long minutes) {
		return LocalDateTime.now().minusMinutes(minutes);
	}


	/**
	 * 获取当前年份
	 *
	 * @return
	 */
	public static String getCurrentYear() {
		Calendar instance = Calendar.getInstance();
		return instance.get(Calendar.YEAR) + "";
	}


	/**
	 * 获取当前月份
	 *
	 * @return
	 */
	public static String getCurrentMonth() {
		Calendar instance = Calendar.getInstance();
		int month = instance.get(Calendar.MONTH) + 1;
		String result;
		if (month < 10) {
			result = "0" + month;
		} else {
			result = month + "";
		}
		return result;
	}

	/**
	 * 获取两个日期之间的所有日期集合
	 */
	public static List<Date> getDatesBetweenTwoDate(Date beginDate, Date endDate) {
		List<Date> lDate = new ArrayList<Date>();
		lDate.add(beginDate);// 把开始时间加入集合
		Calendar cal = Calendar.getInstance();
		// 使用给定的 Date 设置此 Calendar 的时间
		cal.setTime(beginDate);
		boolean bContinue = true;
		while (bContinue) {
			// 根据日历的规则，为给定的日历字段添加或减去指定的时间量
			cal.add(Calendar.DAY_OF_MONTH, 1);
			// 测试此日期是否在指定日期之后
			if (endDate.after(cal.getTime())) {
				lDate.add(cal.getTime());
			} else {
				break;
			}
		}
		lDate.add(endDate);// 把结束时间加入集合
		return lDate;
	}

	//计算两个日期相差年数
	public static int yearDateDiff(String startDate, String endDate) {
		Calendar calBegin = Calendar.getInstance(); //获取日历实例
		Calendar calEnd = Calendar.getInstance();
		calBegin.setTime(stringTodate(startDate, "yyyy")); //字符串按照指定格式转化为日期
		calEnd.setTime(stringTodate(endDate, "yyyy"));
		return calEnd.get(Calendar.YEAR) - calBegin.get(Calendar.YEAR);
	}

	//字符串按照指定格式转化为日期
	public static Date stringTodate(String dateStr, String formatStr) {
		// 如果时间为空则默认当前时间
		Date date = null;
		SimpleDateFormat format = new SimpleDateFormat(formatStr);
		if (dateStr != null && !dateStr.equals("")) {
			String time = "";
			try {
				Date dateTwo = format.parse(dateStr);
				time = format.format(dateTwo);
				date = format.parse(time);
			} catch (ParseException e) {
				e.printStackTrace();
			}

		} else {
			String timeTwo = format.format(new Date());
			try {
				date = format.parse(timeTwo);
			} catch (ParseException e) {
				e.printStackTrace();
			}
		}
		return date;
	}


	//检验字符串是否为合法的格式日期格式（"yyyy-MM-dd hh:mm:ss"）
	public static boolean checkStrMatchYmdhms(String str) {
		try {
			format_ymdhms.parse(str);
		} catch (Exception e) {
			return false;
		}
		return true;
	}

	//检验字符串是否为合法的格式日期格式（"yyyy-MM-dd hh:mm:ss"）
	public static boolean checkStrMatchYmd(String str) {
		try {
			format_ymd.parse(str);
		} catch (Exception e) {
			return false;
		}
		return true;
	}

	public static Long toTime(String str) {
		try {
			return format.parse(str).getTime();
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return Long.valueOf(0);
	}

	public static Date toDate(String str) {
		try {
			return format.parse(str);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return null;
	}

	public static boolean convertDate(String date) {
		boolean result = false;
		if (StringUtils.isNotBlank(date)) {
			try {
				format.parse(date.trim());
				result = true;
			} catch (Exception e) {
				result = false;
			}
		}
		return result;

	}

	public static long getDateDifferDay(String beginDate, String endDate) throws Exception {
		Date beginTime = null;
		if (beginDate.length() > 10) {
			beginTime = DateUtils.getDate(beginDate, DateUtils.format_ymdhms);
		} else if (beginDate.length() == 10) {
			beginTime = formatymd.parse(beginDate);
		}
		Date endTime = null;
		if (endDate.length() > 10) {
			endTime = DateUtils.getDate(endDate, DateUtils.format_ymdhms);
		} else if (endDate.length() == 10) {
			endTime = formatymd.parse(endDate);
		}
		long nd = 1000 * 24 * 60 * 60;
		long nh = 1000 * 60 * 60;
		// long ns = 1000;
		// 获得两个时间的毫秒时间差异
		long diff = endTime.getTime() - beginTime.getTime();
		// 计算差多少小时
		long hour = diff % nd / nh;
		return hour;
	}


	/**
	 * 查询某个日期（date）在近多少（days）天之内
	 *
	 * @param date
	 * @param days
	 * @return
	 */
	public static boolean dateInDays(Date date, int days) {
		Date deadlineDate = addDay(new Date(), -days);
		return date.after(deadlineDate);
	}

	/*
	 * 将时间戳转换为时间
	 */
	public static String stampToDate(Long s) {
		String res;
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date date = new Date(s);
		res = simpleDateFormat.format(date);
		return res;
	}

	/*
	 * 将时间转换为时间戳
	 */
	public static String dateToStamp(String s) throws ParseException {
		String res;
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
		Date date = simpleDateFormat.parse(s);
		long ts = date.getTime();
		res = String.valueOf(ts);
		return res;
	}

	/**
	 * 时间戳转换成日期格式字符串
	 *
	 * @param seconds 精确到毫秒的字符串
	 * @param format
	 * @return
	 */
	public static String timeStamp2Date(String seconds, String format) {
		if (seconds == null || seconds.isEmpty() || seconds.equals("null")) {
			return "";
		}
		if (format == null || format.isEmpty()) {
			format = "yyyy-MM-dd HH:mm:ss";
		}
		SimpleDateFormat sdf = new SimpleDateFormat(format);
		return sdf.format(new Date(Long.valueOf(seconds)));
	}
	/**
	 * 将java.util.Date 转换为java8 的java.time.LocalDateTime,
	 */
	public static LocalDateTime dateConvertToLocalDateTime(Date date) {
		//return date.toInstant().atOffset(ZoneOffset.of("+8")).toLocalDateTime();
		return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
	}

	/**
	 * 将localDateTime转成date
	 * @return
	 */
	public static Date LocalTimeToUdate(LocalDateTime attribute) {
		return Date.from(attribute.atZone(ZoneId.systemDefault()).toInstant());
	}

}
